/**
 * <copyright>
 * </copyright>
 *
 * $Id$
 */
package bpel2rep.version.store.impl;

import bpel2rep.version.StateName;
import java.io.IOException;
import java.util.List;

import bpel2rep.exception.DuplicateVersionException;
import bpel2rep.exception.UnknownStateNameException;
import bpel2rep.process.ProcessPackage;
import bpel2rep.version.Version;
import bpel2rep.version.VersionId;
import bpel2rep.version.VersionPackage;

import bpel2rep.version.impl.VersionIdImpl;
import bpel2rep.version.store.StorePackage;
import bpel2rep.version.store.TeneoStore;


import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.impl.EObjectImpl;
import org.eclipse.emf.teneo.hibernate.HbDataStore;
import org.hibernate.Hibernate;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;

import executable.ExecutablePackage;

/**
 * <!-- begin-user-doc --> An implementation of the model object '
 * <em><b>Teneo Store</b></em>'. <!-- end-user-doc -->
 * <p>
 * </p>
 *
 * @generated
 */
public class TeneoStoreImpl extends EObjectImpl implements TeneoStore {
	private HbDataStore hds;
	private SessionFactory sf;

	/**
	 * <!-- begin-user-doc --> <!-- end-user-doc -->
	 * @generated
	 */
	protected TeneoStoreImpl() {
		super();
	}

	protected TeneoStoreImpl(HbDataStore datastore) {
		this.hds = datastore;
		this.hds.setEPackages(new EPackage[] { ProcessPackage.eINSTANCE,
				ExecutablePackage.eINSTANCE, VersionPackage.eINSTANCE });
		this.hds.initialize();
		this.sf = hds.getSessionFactory();
	}

	/**
	 * <!-- begin-user-doc --> <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	protected EClass eStaticClass() {
		return StorePackage.Literals.TENEO_STORE;
	}

	/**
	 * <!-- begin-user-doc --> <!-- end-user-doc -->
	 * 
	 * @generated NOT
	 */
	public void save(Version v) {
		Session session = this.sf.openSession();
		session.beginTransaction();
		// TODO: using transaction
		// now using cascade save the feature of transaction can
		// be guaranted. save all contained object separate to ensure
		// transactions
		// session.save(v.getMetaInfo());
		// session.save(v.getPredecessor());
		// session.save(v.getProcess());
		// session.save(v.getVersionState());
		// session.save(v.getVersionId());
		session.save(v);
		session.getTransaction().commit();
		session.close();
	}

	/**
	 * <!-- begin-user-doc --> <!-- end-user-doc -->
	 * 
	 * @generated NOT
	 */
	// TODO: return a list of version is logic.
	//
	public Version retrieve(String processId) {
		Session session = this.sf.openSession();
		session.beginTransaction();
		Query q = session.createQuery("FROM Version v WHERE v.process.id='"
				+ processId + "'");
		List<bpel2rep.version.Version> vs = q.list();
		bpel2rep.version.Version v = (bpel2rep.version.Version) vs.get(0);
		session.close();
		return v;
	}

	/**
	 * <!-- begin-user-doc --> <!-- end-user-doc -->
	 * @generated
	 */
	public void delete() {
		// TODO: implement this method
		// Ensure that you remove @generated or mark it @generated NOT
		throw new UnsupportedOperationException();
	}

	/**
	 * <!-- begin-user-doc --> <!-- end-user-doc -->
	 * 
	 * @throws Exception
	 *             duplicatedVersionException
	 * @generated NOT
	 */
	public Version retrieve(String processId, VersionId versionId)
			throws Exception {
		Session session = this.sf.openSession();
		session.beginTransaction();

		String queryString = 
			"from Version v where v.process.id = :processId "
			+ "and v.versionId.majorID = :majorId "
			+ "and v.versionId.minorID = :minorId";

		Query q = session.createQuery(queryString)
			.setString("processId",	processId)
			.setInteger("majorId", versionId.getMajorID())
			.setInteger("minorId", versionId.getMinorID());

//		 String queryString =
//		 "from Version v where v.process.id = :processId "
//		 + "and v.versionId = :versionId";
//		 Query q = session.createQuery(queryString)
//		 .setString("processId", processId)
//		//in order to use Hibernate.custom the DataType must implement UserType interface
//		 .setParameter("versionId", versionId, Hibernate.custom(VersionId.class));

		List<bpel2rep.version.Version> vs = q.list();
		bpel2rep.version.Version v = null;
		if (vs.size() == 1) {
			v = (bpel2rep.version.Version) vs.get(0);
		} else {
			throw new Exception("duplicated version Exception. " + vs.size()
					+ " versions are found");
		}
		session.close();
		return v;
	}

	/**
	 * <!-- begin-user-doc -->
	 * to test whether the version is already in the repository
	 * @param version target version
	 * @return boolean. if the version in the repository return true, else return false
	 * <!-- end-user-doc -->
	 * @throws DuplicateVersionException 
	 * @generated NOT
	 */
	public boolean inStore(Version version) throws DuplicateVersionException {
		Session session = this.sf.openSession();
		session.beginTransaction();

		String queryString = 
			"from Version v where v.process.id = :processId "
			+ "and v.versionId.majorID = :majorId "
			+ "and v.versionId.minorID = :minorId";

		Query q = session.createQuery(queryString)
			.setString("processId",	version.getProcess().getId())
			.setInteger("majorId", version.getVersionId().getMajorID())
			.setInteger("minorId", version.getVersionId().getMinorID());

		List<bpel2rep.version.Version> vs = q.list();
		session.close();
		if (vs.size() == 1) {
			return true;
		} else if (vs.size() == 0) {
			return false;
		} else {
			throw new DuplicateVersionException("duplicated version Exception. " + vs.size()
					+ " versions are found");
		}
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated NOT
	 */
	public StateName getStateName(String processId, VersionId versionId) {
		StateName st = null;
		try{
			st = this.retrieve(processId, versionId).getStateName();
		}catch(Exception e){
			e.printStackTrace();
		}
		return st;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated NOT
	 */
	public void update(Version version) {
		Session session = this.sf.openSession();
		session.beginTransaction();
		session.update(version);
		session.getTransaction().commit();
		session.close();
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @throws DuplicateVersionException 
	 * @generated NOT
	 */
	public void updateState(String processId, VersionId versionId, StateName newStateName) throws DuplicateVersionException {
		Session session = this.sf.openSession();
		session.beginTransaction();
		String queryString = 
			"from Version v where v.process.id = :processId "
			+ "and v.versionId.majorID = :majorId "
			+ "and v.versionId.minorID = :minorId";

		Query q = session.createQuery(queryString)
			.setString("processId",	processId)
			.setInteger("majorId", versionId.getMajorID())
			.setInteger("minorId", versionId.getMinorID());
		List<bpel2rep.version.Version> vs = q.list();
		bpel2rep.version.Version v = null;
		if (vs.size() == 1) {
			v = (bpel2rep.version.Version) vs.get(0);
		} else {
			throw new DuplicateVersionException("duplicated version Exception. " + vs.size()
					+ " versions are found");
		}
		try {
			v.setStateName(newStateName);
		} catch (UnknownStateNameException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		session.update(v);
		session.getTransaction().commit();
		session.close();
	}

} // TeneoStoreImpl
